【流畅的python】16.1 - 生成器如何进化成协程
在生成器中加入yield关键字后,生成器调用方可以向生成器传入值,只需要使用.send(...)方法就可以传送数据。发送的数据会成为生成器函数中yield表达式的值。所以生成器可以作为协程使用。
协程是指一个过程,在这个过程中与调用方协作,产出由调用方提供的值。(协程并不等于生成器)
.send(...)方法是生成器API中增加的方法(在python2.5实现的),除了这个方法外,还添加了.throw(...)和.close(..)方法:
- throw()方法是让调用方抛出异常, 在生成器中处理
- close()方法则是终止生成器
1 def gg(): 2 print('a') 3 while True: 4 b = yield 5 print(b) 6 n = gg() 7 n.send(None) # 预激活协程,让函数gg运行到b = yield这一句 8 print('-') 9 n.send('b') # 给函数gg中的yield传值 10 n.throw(Exception,'value error') # 让调用方抛出异常,在生成器中处理
1 # 输出为: 2 3 a 4 - 5 b 6 Traceback (most recent call last): 7 File "c:/Users/heyufei/Desktop/test.py", line 20, in <module> 8 n.throw(Exception,'value error') # 让调用方抛出异常,在生成器中处理 9 File "c:/Users/heyufei/Desktop/test.py", line 14, in gg 10 b = yield 11 Exception: value error
.close(...)方法
1 def gg(): 2 print('a') 3 while True: 4 b = yield 5 print(b) 6 n = gg() 7 n.send(None) # 预激活协程,让函数gg运行到b = yield这一句 8 print('-') 9 n.send('b') # 给函数gg中的yield传值 10 n.close() # 终止生成器 11 n.send('bb') # 这句会报错
1 # 结果为: 2 a 3 - 4 b 5 Traceback (most recent call last): 6 File "c:/Users/heyufei/Desktop/test.py", line 22, in <module> 7 n.send('bb') # 给函数gg中的yield传值 8 StopIteration
在python3.3后,对生成器函数句法做了两处改动,以更好地作为协程使用:
生成器可以返回一个值,在这之前,如果在生成器中给return 语句提供值,会抛出SyntaxError错误
新引入了yield from句法,使用它可以把复杂的生成器重构成小型的嵌套生成器,省去了之前把生成器的工作委托给子生成器所需的大量样板代码